export default class MyPromise {
  constructor(fn) {
    try {
      fn(this.resolve, this.reject); //fn是调用者传递的方法，立即执行
    } catch (error) {
      this.reject(error);
    }
  }
  /**
   * @description 定义成员变量
   */
  status = MyPromise.status.PENDING; //初始化实例的状态
  success = null; //初始化成功的值
  error = null; //初始化失败的值
  successCb = []; //初始化成功回调
  errorCb = []; //初始化失败回调
  /**
   * @description 成功的方法
   */
  resolve = (success) => {
    //状态一旦被修改不可逆
    if (this.status !== MyPromise.status.PENDING) {
      return;
    }
    this.status = MyPromise.status.FULFILLED; //执行成功改变状态为成功
    this.success = success;
    this.successCb.forEach((cb) => {
      cb();
    });
    this.successCb = [];
  };
  /**
   * @description 失败的方法
   */
  reject = (error) => {
    //状态一旦被修改不可逆
    if (this.status !== MyPromise.status.PENDING) {
      return;
    }
    this.status = MyPromise.status.REJECTED; //执行错误改变状态为失败
    this.error = error;
    this.errorCb.forEach((cb) => {
      cb();
    });
    this.errorCb = [];
  };

  /**
   *
   * @param {Function} successCb
   * @param {Function} errorCb
   * @description 状态改变要执行的方法
   */
  then = (successCb, errorCb) => {
    successCb = successCb ? successCb : (v) => v;
    errorCb = errorCb
      ? errorCb
      : (v) => {
          throw v;
        };
    let promise2 = new MyPromise((resolve, reject) => {
      //判断状态，执行相应的回调
      if (this.status === MyPromise.status.FULFILLED) {
        setTimeout(() => {
          try {
            MyPromise.resolvePromise(
              promise2,
              successCb(this.success),
              resolve,
              reject
            );
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.status === MyPromise.status.REJECTED) {
        setTimeout(() => {
          try {
            MyPromise.resolvePromise(
              promise2,
              reject(errorCb(this.error)),
              resolve,
              reject
            );
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        //缓存
        this.successCb.push(() => {
          setTimeout(() => {
            try {
              MyPromise.resolvePromise(
                promise2,
                successCb(this.success),
                resolve,
                reject
              );
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        this.errorCb.push(() => {
          setTimeout(() => {
            try {
              MyPromise.resolvePromise(
                promise2,
                reject(errorCb(this.error)),
                resolve,
                reject
              );
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
    return promise2;
  };

  /**
   *
   * @param {Function} cb
   * @description 异常通知
   */
  catch = (cb) => {
    return this.then(null, cb);
  };

  /**
   * @param {Function} cb 传递的回调
   * @description after通知
   * @returns {MyPromise}
   */
  finally = (cb) => {
    return this.then(
      (v) => {
        return MyPromise.resolve(cb()).then(() => {
          return v;
        });
      },
      (e) => {
        return MyPromise.resolve(cb()).then(() => {
          throw e;
        });
      }
    );
  };

  /**
   * @description 静态的resolve
   * @param {any} data
   * @returns {MyPromise}
   */
  static resolve = (data) => {
    if (data instanceof MyPromise) {
      return data;
    }
    return new MyPromise((resolve, reject) => {
      resolve(data);
    });
  };

  static reject = (data) => {
    if (data instanceof MyPromise) {
      return data;
    }
    return new MyPromise((resolve, reject) => {
      if (data instanceof Error) {
        reject(data);
      }
      reject(new Error(data));
    });
  };

  /**
   *
   * @param {Array<any>} arr
   * @description 竞争
   * @returns {MyPromise}
   */
  static race = (arr) => {
    let num = 0;
    const pushAndCheck = (value, resolve, reject) => {
      if (!value) {
        num++;
        if (num === arr.length) {
          reject(new Error('全部失败'));
        }
      } else {
        resolve(value);
      }
    };
    return new MyPromise((resolve, reject) => {
      arr.forEach((ele) => {
        if (ele instanceof MyPromise) {
          ele.then(
            (v) => {
              pushAndCheck(v, resolve, reject);
            },
            (e) => {
              return pushAndCheck(null, resolve, reject);
            }
          );
        } else {
          pushAndCheck(ele, resolve, reject);
        }
      });
    });
  };
  /**
   *
   * @param {Array<any>} arr
   * @description MyPromise.all
   * @returns {MyPromise}
   */
  static all = (arr) => {
    let res = [];
    let num = 0;
    const pushAndCheck = (key, value, resolve) => {
      res[key] = value;
      num++;
      if (num === arr.length) {
        resolve(res);
      }
    };
    return new MyPromise((resolve, reject) => {
      arr.forEach((ele, index) => {
        if (ele instanceof MyPromise) {
          ele.then(
            (v) => {
              pushAndCheck(index, v, resolve);
            },
            (e) => {
              return reject(e);
            }
          );
        } else {
          pushAndCheck(index, ele, resolve);
        }
      });
    });
  };

  /**
   * @param {MyPromise} promise2
   * @param {any} res
   * @param {Function} resolve
   * @param {Function} reject
   * @description 判断如何传递给下个then
   */
  static resolvePromise = (promise2, res, resolve, reject) => {
    if (promise2 === res) {
      reject(new Error('循环调用'));
      return;
    }
    if (res instanceof MyPromise) {
      res.then(resolve, reject);
    } else {
      resolve(res);
    }
  };
  /**
   * @description 定义静态属性---状态枚举
   */
  static status = {
    PENDING: 'pending', // 等待
    FULFILLED: 'fulfilled', // 成功
    REJECTED: 'rejected', // 失败
  };
}
